﻿module FTPServerSetting

open System
open System.Xml
open System.Xml.Linq
open System.IO
open System.Diagnostics
open Extensions
open Common

module private Until =
 
    ///使用string的replace修改userName 和userPwdHex即可
    let  userXmlTemplate =
        "<User Name=\"userName\">
              <Option Name=\"Pass\">userPwdHex</Option>
              <Option Name=\"Group\">YLs</Option>
              <Option Name=\"Bypass server userlimit\">2</Option>
              <Option Name=\"User Limit\">0</Option>
              <Option Name=\"IP Limit\">0</Option>
              <Option Name=\"Enabled\">2</Option>
              <Option Name=\"Comments\"></Option>
              <Option Name=\"ForceSsl\">2</Option>
              <IpFilter>
                <Disallowed />
                <Allowed />
              </IpFilter>
              <Permissions>
                <Permission Dir=\"F:\FTPServer\userName\">
                  <Option Name=\"FileRead\">1</Option>
                  <Option Name=\"FileWrite\">1</Option>
                  <Option Name=\"FileDelete\">0</Option>
                  <Option Name=\"FileAppend\">0</Option>
                  <Option Name=\"DirCreate\">0</Option>
                  <Option Name=\"DirDelete\">0</Option>
                  <Option Name=\"DirList\">1</Option>
                  <Option Name=\"DirSubdirs\">1</Option>
                  <Option Name=\"IsHome\">1</Option>
                  <Option Name=\"AutoCreate\">0</Option>
                </Permission>
              </Permissions>
              <SpeedLimits DlType=\"0\" DlLimit=\"10\" ServerDlLimitBypass=\"2\" UlType=\"0\" UlLimit=\"10\" ServerUlLimitBypass=\"2\">
                <Download />
                <Upload />
              </SpeedLimits>
            </User>
        "
    let  BuildUser name pwd =
        let pwdHex =pwd |> HashAlgorithm.getHex_MD5
        userXmlTemplate.Replace("userName",name).Replace("userPwdHex",pwdHex)
        |> XElement.Parse


    /// path -> name -> dir
    let  createDir  (path:string) (name :string)=
        let dir =conbindPath path name 
        dir |>Directory.CreateDirectory |>ignore
        dir
    ///delete all files on  dir   before delete dir 
    /// path -> name -> unit
    let DeleteDir path name =
        let dir =conbindPath path name
        let files = Directory.GetFiles(dir)
        files|>Array.iter (fun fname -> File.Delete fname)
        dir|> Directory.Delete
        

open Until
    
type SettingManager = 
    val  configPath:string 
    val private doc :XDocument
    new(cp:string) =
        let fs =File.OpenRead(cp)
        let doc' =XDocument.Load(fs)
        fs.Dispose()
        { configPath =cp;
            doc =doc'
        }
    member private m.saveAndReloadConfig()=
        m.saveConfig  ()
        m.reloadConfig()
    member private m.saveConfig ()=
            use fs = File.OpenWrite(m.configPath)
            use sw = new StreamWriter(fs)
            sw.Write(m.doc.ToString())
    member m.reloadConfig ()=
        let dir =getDir m.configPath
        let exePath= dir + "\\FileZilla server.exe"
        Process.Start(exePath,"/reload-config").WaitForExit()

    member m.DeleteUser name =
        let user = m.doc.findUser name
        user.Remove()
        m.saveAndReloadConfig()

    member m.AddUser name pwd =
        let user = BuildUser name pwd 
        m.doc.addUser user
        m.saveAndReloadConfig()
    member m.ResetUserPassword name newPwd =
        let u =m.doc.findUser name
        u.updateUserPassword (newPwd|>HashAlgorithm.getHex_MD5)
        m.saveAndReloadConfig()
    member m.RandomPassword name pwdLen=
        let pwd =HashAlgorithm.randomWord pwdLen 
        m.ResetUserPassword name pwd
        m.saveAndReloadConfig()
        pwd
    member m.GetHomeDir() =
            m.doc.Element("FileZillaServer")
                .Element("Groups")
                .Element("Group",fun g->g.Attribute("Name").Value="YLs")
                .Element("Permissions").Element("Permission").Attribute("Dir").Value 
    /// name -> dir
    member m.CreateUserOnDisk name =
            let dir =m.GetHomeDir()
            createDir dir name
    member m.GetUserHomeDir name =
        let user = m.doc.findUser name
        user.Element("Permissions").Element("Permission").Attribute("Dir").Value
    /// 工作项文件夹名字是 boyName&grilName\模板名
    ///返回相对路径
    member m.AddWorkItemDir userName boyName grilName tempLateName=
        let dir = m.GetUserHomeDir userName
        let dir' =createDir dir (boyName+"&"+grilName)
        createDir dir' tempLateName |>ignore 
        userName+"\\"+boyName+"&"+grilName+"\\"+tempLateName
    /// 工作项文件夹名字就是boyName 与grilName 的拼接
    member m.DeleteWorkItemDir userName boyName grilName =
        let dir = m.GetUserHomeDir userName
        DeleteDir dir (boyName+"&"+grilName)

//   #r "System.Xml.Linq";;        
//   #load "HashAlgorithm.fs";;
//   #load "Extensions.fs"
//   #load "FTPServerSetting.fs";;
//    open FTPServerSetting;;
//   let sm =new SettingManager(@"E:\Program Files (x86)\FileZilla Server\FileZilla Server.xml");;
//   sm.AddUser "test" "test";;
//   sm.ResetUserPassword "test" "jzjz";;
//   sm.RandomPassword "test" 8

//cool Success
